package com.cxx.purchasecharge.component.controller;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.cxx.purchasecharge.component.bean.AccountingBean;
import com.cxx.purchasecharge.component.bean.ActionResult;
import com.cxx.purchasecharge.component.bean.ActionResult.ActionResultStatus;
import com.cxx.purchasecharge.component.bean.DataGridRequestForm;
import com.cxx.purchasecharge.component.bean.GenericPagingResult;
import com.cxx.purchasecharge.component.bean.LoginUser;
import com.cxx.purchasecharge.component.bean.PCApplicationContext;
import com.cxx.purchasecharge.component.bean.SearchRequestForm;
import com.cxx.purchasecharge.component.utils.AjaxUtils;
import com.cxx.purchasecharge.component.utils.BeanConvertUtils;
import com.cxx.purchasecharge.component.utils.ComponentConstants;
import com.cxx.purchasecharge.component.utils.MessageProperties;
import com.cxx.purchasecharge.core.model.AccountingSearchForm;
import com.cxx.purchasecharge.core.model.persistence.Accounting;
import com.cxx.purchasecharge.dal.AccountingDao;
import com.cxx.purchasecharge.service.QueryService;

@Controller
@RequestMapping ("/accounting")
public class AccountingManager extends GenericController <AccountingBean>
{
    private static final Logger logger = Logger.getLogger (AccountingManager.class);

    @Autowired
    private AccountingDao accountingDao;
    @Autowired
    private QueryService queryService;
    @Autowired
    private PCApplicationContext pcContext;

    public AccountingManager ()
    {
        super.setViewName("accountingManagement");
    }

    @Override
    public String getModelBySearchForm(
        DataGridRequestForm dataGridRequestForm,
        SearchRequestForm searchRequestForm,
        HttpServletRequest request)
    {
        logger.debug (dataGridRequestForm);
        int page = dataGridRequestForm.getPage () - 1;
        int size = dataGridRequestForm.getRows ();
        String sortField = parseSortField (dataGridRequestForm.getSort ());
        String order = dataGridRequestForm.getOrder ();
        Pageable pageable = new PageRequest (page, size, new Sort ("asc".equalsIgnoreCase (order) ? Direction.ASC
                                                                                                 : Direction.DESC,
                                                                   sortField));
        LoginUser loginUser = null;
        try
        {
            loginUser = pcContext.getLoginUser (request);
        }
        catch (Exception e)
        {
            logger.warn("Get login user failed", e);
        }
        
        if (null != loginUser)
        {
            AccountingSearchForm searchForm = BeanConvertUtils.searchRequestForm2AccountingSearchForm (searchRequestForm);
            Page <Accounting> expensePage = accountingDao.findPageAccountingBy (searchForm, pageable);
            float sumOutMoney = accountingDao.countExpenseBy (searchForm);
            float sumInMoney = accountingDao.countIncomeBy (searchForm);
            List <Map <String, String>> footer = new ArrayList <Map <String, String>> ();
            Map <String, String> map = new HashMap <String, String> ();
            map.put ("mode", "支出合计");
            map.put ("money", sumOutMoney + "");
            footer.add (map);
            map = new HashMap <String, String> ();
            map.put ("mode", "收入合计");
            map.put ("money", sumInMoney + "");
            footer.add (map);
            map = new HashMap <String, String> ();
            map.put ("mode", "总计");
            map.put ("money", (sumInMoney - sumOutMoney) + "");
            footer.add (map);

            long total = expensePage.getTotalElements ();
            GenericPagingResult <AccountingBean> expensePagingResult = new GenericPagingResult <AccountingBean> ();
            expensePagingResult.setRows (BeanConvertUtils.accountingList2AccountingBeanList (expensePage.getContent ()));
            expensePagingResult.setTotal (total);
            expensePagingResult.setFooter (footer);

            JSONObject jsonObject = JSONObject.fromObject (expensePagingResult);
            return jsonObject.toString ();
        }
        return "";
    }

    @Override
    public String addModel(AccountingBean bean, BindingResult result, HttpServletRequest request)
    {
        if (result.hasErrors ())
        {
            logger.error (result.getAllErrors ());
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            Accounting expense = BeanConvertUtils.accountingBean2Accounting (bean);
            expense.setUpdated(expense.getCreated());
            String userId = AjaxUtils.getUserIdFromRequest(pcContext, request);
            if(null != userId) 
            {
                expense.setUserCreatedBy(queryService.getUniqueIdByUserId(userId));
                expense.setUserUpdatedBy(queryService.getUniqueIdByUserId(userId));
            }
            ActionResult ar = ActionResult.createActionResult ().build ();

            try
            {
                accountingDao.save (expense);
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_ADD_SUCCESS,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
            }
            catch (Exception e)
            {
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_ADD_FAIL,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
                logger.error (e.getMessage (), e);
            }

            return AjaxUtils.getJsonObject (ar);
        }
    }

    @Override
    public String updateModel(AccountingBean bean, BindingResult result, HttpServletRequest request)
    {
        if (result.hasErrors ())
        {
            logger.error (result.getAllErrors ());
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            Accounting expense = BeanConvertUtils.accountingBean2Accounting (bean);
            expense.setUpdated(new Date());
            String userId = AjaxUtils.getUserIdFromRequest(pcContext, request);
            if(null != userId) 
            {
                expense.setUserUpdatedBy(queryService.getUniqueIdByUserId(userId));
            }
            ActionResult ar = ActionResult.createActionResult ().build ();

            try
            {
                accountingDao.save (expense);
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_SUCCESS,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_SUCCESS,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
            }

            return AjaxUtils.getJsonObject (ar);
        }
    }

    @Override
    public String deleteModels(@RequestParam String ids, HttpServletRequest request)
    {
        if (null != ids && ids.trim ().length () > 0)
        {
            List <Accounting> expenses = new ArrayList <Accounting> ();
            Accounting expense;
            if (ids.indexOf (";") != -1)
            {
                String[] idArr = ids.split (";");
                for (String typeId : idArr)
                {
                    expense = new Accounting ();
                    long expenseId = Long.parseLong (typeId);
                    expense.setId (expenseId);
                    expenses.add (expense);
                }
            }
            else
            {
                expense = new Accounting ();
                long expenseId = Long.parseLong (ids);
                expense.setId (expenseId);
                expenses.add (expense);
            }

            ActionResult ar = ActionResult.createActionResult ().build ();
            try
            {
                accountingDao.delete (expenses);
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_DELETE_SUCCESS,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_DELETE_SUCCESS,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
            }

            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            logger.error (ActionResultStatus.BAD_REQUEST + " ids=" + ids + " when delete expense type");
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
    }

    private String parseSortField (final String sortField)
    {
        String sortFieldAfterParse = ComponentConstants.EXPENSE_CREATE;
        if (!StringUtils.isBlank (sortField))
        {
            sortFieldAfterParse = sortField;
            if (ComponentConstants.EXPENSE_TYPE.equalsIgnoreCase (sortField))
            {
                sortFieldAfterParse = ComponentConstants.EXPENSE_TYPE_DOT_NAME;
            }
            else if (ComponentConstants.EXPENSE_CREATE_DATE.equalsIgnoreCase (sortField))
            {
                sortFieldAfterParse = ComponentConstants.EXPENSE_CREATE;
            }
            else if (ComponentConstants.EXPENSE_UPDATE_DATE.equalsIgnoreCase (sortField))
            {
                sortFieldAfterParse = ComponentConstants.EXPENSE_UPDATE;
            }
        }
        return sortFieldAfterParse;
    }

}
